2009-01-28 21:16:31 +01:00
/*****************************************************************************
*
* 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$
2009-05-12 00:06:48 +02:00
# include <iostream>
# include <fstream>
# include <stdexcept>
2009-01-28 21:16:31 +01:00
# include "ogr_datasource.hpp"
# include "ogr_featureset.hpp"
2009-05-12 00:06:48 +02:00
# include "ogr_index_featureset.hpp"
// mapnik
2009-01-29 05:20:34 +01:00
# include <mapnik/ptree_helpers.hpp>
2009-05-12 00:06:48 +02:00
# include <mapnik/geom_util.hpp>
2009-01-28 21:16:31 +01:00
2009-03-30 22:19:57 +02:00
// boost
2009-05-12 00:06:48 +02:00
# include <boost/algorithm/string.hpp>
2009-03-30 22:19:57 +02:00
2009-01-28 21:16:31 +01:00
using mapnik : : datasource ;
using mapnik : : parameters ;
DATASOURCE_PLUGIN ( ogr_datasource )
2009-12-16 21:02:06 +01:00
using mapnik : : box2d ;
2009-01-28 21:16:31 +01:00
using mapnik : : coord2d ;
using mapnik : : query ;
using mapnik : : featureset_ptr ;
using mapnik : : layer_descriptor ;
using mapnik : : attribute_descriptor ;
using mapnik : : datasource_exception ;
2009-05-12 00:06:48 +02:00
using mapnik : : filter_in_box ;
using mapnik : : filter_at_point ;
2009-01-28 21:16:31 +01:00
2010-10-24 08:34:18 +02:00
ogr_datasource : : ogr_datasource ( parameters const & params , bool bind )
2009-01-28 21:16:31 +01:00
: datasource ( params ) ,
extent_ ( ) ,
2009-01-29 05:20:34 +01:00
type_ ( datasource : : Vector ) ,
2009-05-12 00:06:48 +02:00
desc_ ( * params . get < std : : string > ( " type " ) , * params . get < std : : string > ( " encoding " , " utf-8 " ) ) ,
indexed_ ( false )
2009-01-28 21:16:31 +01:00
{
boost : : optional < std : : string > file = params . get < std : : string > ( " file " ) ;
2010-11-16 18:14:22 +01:00
boost : : optional < std : : string > string = params . get < std : : string > ( " string " ) ;
if ( ! file & & ! string ) throw datasource_exception ( " missing <file> or <string> parameter " ) ;
2009-01-28 21:16:31 +01:00
2010-11-16 18:14:22 +01:00
multiple_geometries_ = * params . get < mapnik : : boolean > ( " multiple_geometries " , false ) ;
2009-01-29 05:20:34 +01:00
2010-11-16 18:14:22 +01:00
if ( string )
{
dataset_name_ = * string ;
}
2009-03-30 22:19:57 +02:00
else
2010-11-16 18:14:22 +01:00
{
boost : : optional < std : : string > base = params . get < std : : string > ( " base " ) ;
if ( base )
dataset_name_ = * base + " / " + * file ;
else
dataset_name_ = * file ;
}
2010-10-24 08:34:18 +02:00
if ( bind )
{
this - > bind ( ) ;
}
}
2009-05-12 00:06:48 +02:00
2010-11-16 18:14:22 +01:00
ogr_datasource : : ~ ogr_datasource ( )
{
if ( is_bound_ )
{
OGRDataSource : : DestroyDataSource ( dataset_ ) ;
}
}
2010-10-24 08:34:18 +02:00
void ogr_datasource : : bind ( ) const
{
if ( is_bound_ ) return ;
2010-11-16 18:14:22 +01:00
// initialize ogr formats
OGRRegisterAll ( ) ;
2010-10-24 08:34:18 +02:00
2009-05-12 00:06:48 +02:00
// open ogr driver
2009-03-30 22:19:57 +02:00
dataset_ = OGRSFDriverRegistrar : : Open ( ( dataset_name_ ) . c_str ( ) , FALSE ) ;
2009-05-08 23:12:53 +02:00
if ( ! dataset_ )
{
std : : string err = CPLGetLastErrorMsg ( ) ;
2010-06-17 12:38:23 +02:00
if ( err . size ( ) = = 0 ) {
2010-11-18 23:59:21 +01:00
throw datasource_exception ( " OGR Plugin: connection failed: " + dataset_name_ + " was not found or is not a supported format " ) ;
2009-05-08 23:12:53 +02:00
} else {
2010-11-18 23:59:21 +01:00
throw datasource_exception ( " OGR Plugin: " + err ) ;
2009-05-08 23:12:53 +02:00
}
}
2009-01-28 21:16:31 +01:00
2009-05-12 00:06:48 +02:00
// initialize layer
2010-06-19 17:13:47 +02:00
2010-10-24 08:34:18 +02:00
boost : : optional < std : : string > layer_by_name = params_ . get < std : : string > ( " layer " ) ;
boost : : optional < unsigned > layer_by_index = params_ . get < unsigned > ( " layer_by_index " ) ;
2010-06-19 17:13:47 +02:00
2010-08-20 23:20:55 +02:00
if ( layer_by_name & & layer_by_index )
throw datasource_exception ( " OGR Plugin: you can only select an ogr layer by name ('layer' parameter) or by number ( ' layer_by_index ' parameter ) , do not supply both parameters " ) ;
if ( layer_by_name )
{
layerName_ = * layer_by_name ;
layer_ = dataset_ - > GetLayerByName ( layerName_ . c_str ( ) ) ;
}
else if ( layer_by_index )
2010-06-19 17:13:47 +02:00
{
2010-08-20 23:59:48 +02:00
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 ( ) ) ;
}
2010-08-20 23:20:55 +02:00
OGRLayer * ogr_layer = dataset_ - > GetLayer ( * layer_by_index ) ;
2010-06-19 17:13:47 +02:00
if ( ogr_layer )
{
OGRFeatureDefn * def = ogr_layer - > GetLayerDefn ( ) ;
if ( def ! = 0 ) {
layerName_ = def - > GetName ( ) ;
layer_ = ogr_layer ;
}
}
}
2010-08-20 23:20:55 +02:00
else
2009-05-08 23:12:53 +02:00
{
2010-08-20 23:20:55 +02:00
std : : ostringstream s ;
2010-11-18 23:59:21 +01:00
s < < " OGR Plugin: missing <layer> or <layer_by_index> parameter, available layers are: " ;
2009-05-08 23:12:53 +02:00
unsigned num_layers = dataset_ - > GetLayerCount ( ) ;
2010-08-20 23:20:55 +02:00
bool found = false ;
2009-05-08 23:12:53 +02:00
for ( unsigned i = 0 ; i < num_layers ; + + i )
{
OGRLayer * ogr_layer = dataset_ - > GetLayer ( i ) ;
OGRFeatureDefn * def = ogr_layer - > GetLayerDefn ( ) ;
if ( def ! = 0 ) {
2010-08-20 23:20:55 +02:00
found = true ;
2010-08-20 23:24:58 +02:00
s < < " ' " < < def - > GetName ( ) < < " ' " ;
2009-05-08 23:12:53 +02:00
}
}
2010-08-20 23:20:55 +02:00
if ( ! found ) {
s < < " None (no layers were found in dataset) " ;
}
throw datasource_exception ( s . str ( ) ) ;
2010-06-19 17:13:47 +02:00
}
2010-08-20 23:20:55 +02:00
if ( ! layer_ )
2010-06-19 17:13:47 +02:00
{
2010-08-20 23:20:55 +02:00
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 ;
s + = " ' in dataset ' " + dataset_name_ + " ' " ;
throw datasource_exception ( s ) ;
2009-05-08 23:12:53 +02:00
}
2009-01-29 17:20:30 +01:00
2009-05-12 00:06:48 +02:00
// initialize envelope
2009-01-29 17:20:30 +01:00
OGREnvelope envelope ;
layer_ - > GetExtent ( & envelope ) ;
extent_ . init ( envelope . MinX , envelope . MinY , envelope . MaxX , envelope . MaxY ) ;
2009-05-12 00:06:48 +02:00
// scan for index file
2010-08-20 23:20:55 +02:00
// 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
2009-12-14 00:30:36 +01:00
size_t breakpoint = dataset_name_ . find_last_of ( " . " ) ;
2009-05-12 00:06:48 +02:00
if ( breakpoint = = std : : string : : npos ) breakpoint = dataset_name_ . length ( ) ;
2010-08-20 23:20:55 +02:00
index_name_ = dataset_name_ . substr ( 0 , breakpoint ) + " .ogrindex " ;
2009-05-12 00:06:48 +02:00
std : : ifstream index_file ( index_name_ . c_str ( ) , std : : ios : : in | std : : ios : : binary ) ;
if ( index_file )
{
indexed_ = true ;
index_file . close ( ) ;
}
2010-08-20 23:20:55 +02:00
// 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 \n " ;
} */
2009-05-12 00:06:48 +02:00
// deal with attributes descriptions
2009-01-28 21:16:31 +01:00
OGRFeatureDefn * def = layer_ - > GetLayerDefn ( ) ;
if ( def ! = 0 )
{
2009-01-29 17:20:30 +01:00
int fld_count = def - > GetFieldCount ( ) ;
for ( int i = 0 ; i < fld_count ; i + + )
2009-01-28 21:16:31 +01:00
{
OGRFieldDefn * fld = def - > GetFieldDefn ( i ) ;
2009-02-18 23:50:12 +01:00
std : : string fld_name = fld - > GetNameRef ( ) ;
2009-01-28 21:16:31 +01:00
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 :
2009-01-29 17:20:30 +01:00
case OFTWideString : // deprecated
2009-01-28 21:16:31 +01:00
desc_ . add_descriptor ( attribute_descriptor ( fld_name , mapnik : : String ) ) ;
break ;
case OFTBinary :
desc_ . add_descriptor ( attribute_descriptor ( fld_name , mapnik : : Object ) ) ;
break ;
2009-01-29 17:20:30 +01:00
case OFTIntegerList :
case OFTRealList :
case OFTStringList :
case OFTWideStringList : // deprecated !
2009-01-28 21:16:31 +01:00
# ifdef MAPNIK_DEBUG
2010-11-18 23:59:21 +01:00
std : : clog < < " OGR Plugin: unhandled type_oid= " < < type_oid < < std : : endl ;
2009-01-28 21:16:31 +01:00
# endif
break ;
2009-01-29 17:20:30 +01:00
case OFTDate :
case OFTTime :
case OFTDateTime : // unhandled !
2009-01-28 21:16:31 +01:00
# ifdef MAPNIK_DEBUG
2010-11-18 23:59:21 +01:00
std : : clog < < " OGR Plugin: unhandled type_oid= " < < type_oid < < std : : endl ;
2009-01-28 21:16:31 +01:00
# endif
2009-01-29 17:20:30 +01:00
desc_ . add_descriptor ( attribute_descriptor ( fld_name , mapnik : : Object ) ) ;
2009-01-28 21:16:31 +01:00
break ;
default : // unknown
# ifdef MAPNIK_DEBUG
2010-11-18 23:59:21 +01:00
std : : clog < < " OGR Plugin: unknown type_oid= " < < type_oid < < std : : endl ;
2009-01-28 21:16:31 +01:00
# endif
break ;
}
}
}
2010-10-24 08:34:18 +02:00
is_bound_ = true ;
2009-01-28 21:16:31 +01:00
}
std : : string ogr_datasource : : name ( )
{
2009-05-08 23:12:53 +02:00
return " ogr " ;
2009-01-28 21:16:31 +01:00
}
int ogr_datasource : : type ( ) const
{
2009-01-29 05:20:34 +01:00
return type_ ;
2009-01-28 21:16:31 +01:00
}
2009-12-16 21:02:06 +01:00
box2d < double > ogr_datasource : : envelope ( ) const
2009-01-28 21:16:31 +01:00
{
2010-10-24 08:34:18 +02:00
if ( ! is_bound_ ) bind ( ) ;
2009-01-28 21:16:31 +01:00
return extent_ ;
}
layer_descriptor ogr_datasource : : get_descriptor ( ) const
{
2010-10-24 08:34:18 +02:00
if ( ! is_bound_ ) bind ( ) ;
2009-01-28 21:16:31 +01:00
return desc_ ;
}
featureset_ptr ogr_datasource : : features ( query const & q ) const
{
2010-10-24 08:34:18 +02:00
if ( ! is_bound_ ) bind ( ) ;
2009-01-28 21:16:31 +01:00
if ( dataset_ & & layer_ )
{
2011-05-26 09:30:49 +02:00
// TODO - actually filter fields!
// http://trac.osgeo.org/gdal/wiki/rfc29_desired_fields
// http://trac.osgeo.org/gdal/wiki/rfc28_sqlfunc
2009-01-28 21:16:31 +01:00
#if 0
std : : ostringstream s ;
s < < " select " ;
std : : set < std : : string > const & props = q . property_names ( ) ;
std : : set < std : : string > : : const_iterator pos = props . begin ( ) ;
std : : set < std : : string > : : const_iterator end = props . end ( ) ;
while ( pos ! = end )
{
s < < " , \" " < < * pos < < " \" " ;
+ + pos ;
2011-04-02 05:45:50 +02:00
}
2009-01-29 17:20:30 +01:00
s < < " from " < < layerName_ ;
// execute existing SQL
OGRLayer * layer = dataset_ - > ExecuteSQL ( s . str ( ) , poly ) ;
// layer must be freed
dataset_ - > ReleaseResultSet ( layer ) ;
2009-01-28 21:16:31 +01:00
# endif
2009-05-12 00:06:48 +02:00
if ( indexed_ )
{
filter_in_box filter ( q . get_bbox ( ) ) ;
return featureset_ptr ( new ogr_index_featureset < filter_in_box > ( * dataset_ ,
* layer_ ,
filter ,
index_name_ ,
desc_ . get_encoding ( ) ,
multiple_geometries_ ) ) ;
}
else
{
return featureset_ptr ( new ogr_featureset ( * dataset_ ,
* layer_ ,
q . get_bbox ( ) ,
desc_ . get_encoding ( ) ,
multiple_geometries_ ) ) ;
}
2009-01-28 21:16:31 +01:00
}
return featureset_ptr ( ) ;
}
featureset_ptr ogr_datasource : : features_at_point ( coord2d const & pt ) const
{
2010-10-24 08:34:18 +02:00
if ( ! is_bound_ ) bind ( ) ;
2009-01-29 17:20:30 +01:00
if ( dataset_ & & layer_ )
{
2009-05-12 00:06:48 +02:00
if ( indexed_ )
{
filter_at_point filter ( pt ) ;
return featureset_ptr ( new ogr_index_featureset < filter_at_point > ( * dataset_ ,
* layer_ ,
filter ,
index_name_ ,
desc_ . get_encoding ( ) ,
multiple_geometries_ ) ) ;
}
else
{
OGRPoint point ;
2011-04-02 05:45:50 +02:00
point . setX ( pt . x ) ;
point . setY ( pt . y ) ;
2009-05-12 00:06:48 +02:00
return featureset_ptr ( new ogr_featureset ( * dataset_ ,
* layer_ ,
point ,
desc_ . get_encoding ( ) ,
multiple_geometries_ ) ) ;
}
2009-01-29 17:20:30 +01:00
}
2009-01-28 21:16:31 +01:00
return featureset_ptr ( ) ;
}